import { Injectable } from '@nestjs/common';
import { Repository } from 'typeorm';
import { InjectRepository } from '@nestjs/typeorm';
import { UserWeapon } from './entities/user-weapon.entity';
import { PageQuery } from '../../../util/entity/page.entity';
import { buildQuery, getRandomFrom } from '../../../util/common-fn';
import { Weapon } from '../weapon/entities/weapon.entity';
import { User } from '../../admin/user/entities/user.entity';
import { Money } from '../money/entities/money.entity';
import { WeaponUp } from '../weapon-up/entities/weapon-up.entity';
import { UserItem } from '../user-item/entities/user-item.entity';
import { UpWeaponResultVo } from './vo/up-weapon-result.vo';
import { RecordService } from '../record/record.service';
import { DictSonService } from '../../admin/dict-son/dict-son.service';
import { DictType } from '../../../util/enum/dict.enum';

@Injectable()
export class UserWeaponService {
  constructor(
    @InjectRepository(UserWeapon)
    private userWeaponRepository: Repository<UserWeapon>,
    private recordService: RecordService,
    private dictSonService: DictSonService,
  ) {}
  async findAll(pageQuery: PageQuery<UserWeapon>, userId: number) {
    const andWhere = { user: { id: userId } };
    const query = buildQuery(pageQuery, andWhere);
    return await this.userWeaponRepository.findAndCount(query);
  }

  findOneWithWeapon(id: number) {
    return this.userWeaponRepository.findOne({
      where: { id },
      relations: {
        weapon: true,
      },
    });
  }

  remove(id: number) {
    return `This action removes a #${id} userWeapon`;
  }

  /**
   * 用户购买装备(交易)
   * @param weaponId
   * @param userId
   */
  async buy(weaponId: number, userId: number) {
    await this.userWeaponRepository.manager
      .transaction(async (tr) => {
        const weapon = await tr.findOneByOrFail(Weapon, { id: weaponId });
        const user = await tr.findOneOrFail(User, {
          where: { id: userId },
          relations: {
            moneys: true,
          },
        });
        // 找到用户付钱的类型,点券还是金币等等
        const userMoney = user.moneys.find(
          (item) => item.priceType === weapon.priceType,
        );

        // 这是处理message
        const priceTypeName = await this.dictSonService.getNameByCode(
          DictType.DnfPriceType,
          weapon.priceType,
        );
        const weaponTypeName = await this.dictSonService.getNameByCode(
          DictType.DnfWeaponType,
          weapon.weaponType,
        );
        const errorMessage = `花费${weapon.price}${priceTypeName},购买${weaponTypeName}:+${weapon.level}『${weapon.name}』`;

        // 钱足够
        if (userMoney.num >= weapon.price) {
          // 先扣钱
          await tr.decrement(Money, { id: userMoney.id }, 'num', weapon.price);
          // 再把装备添加到用户装备上
          const userWeapon = new UserWeapon();
          userWeapon.user = user;
          userWeapon.weapon = weapon;
          userWeapon.level = weapon.level;
          // 通过武器的level,查找到该武器的名望和数值
          const weaponUp = await tr.findOneBy(WeaponUp, {
            weaponType: weapon.weaponType,
            level: weapon.level,
          });
          if (weaponUp) {
            userWeapon.fame = weaponUp.fame;
            userWeapon.num = weaponUp.num;
          }
          const result = await tr.save(UserWeapon, userWeapon);
          return {
            userWeaponId: result.id,
            errorMessage,
          };
        } else {
          // 钱不够
          throw new Error(`想要${errorMessage},但是钱不够啦.`);
        }
      })
      .then(async (result) => {
        await this.recordService.insertValues({
          user: { id: userId },
          success: 1,
          type: 3,
          weapon: { id: weaponId },
          errorMessage: result.errorMessage,
          userWeapon: { id: result.userWeaponId },
        });
      })
      .catch(async (err: Error) => {
        await this.recordService.insertValues({
          user: { id: userId },
          success: 0,
          type: 3,
          weapon: { id: weaponId },
          errorMessage: err.message,
        });
        throw new Error(err.message);
      });
  }

  /**
   * 增幅装备
   * @param id
   * @param upType 增幅类型1-正常 2-增幅器
   * @param userId
   */
  async weaponUp(id: number, upType: number, userId: number) {
    return await this.userWeaponRepository.manager
      .transaction(async (tr) => {
        /**
         *  0.获取用户的物品信息(1-增幅器和2-矛盾)
         *  1.通过userId获取money
         *  2.通过id获取用户装备信息,包括装备
         *  3.通过 weaponType(装备类型),level+1(装备等级)获取weaponUp装备升级信息
         *  4.如果用户通过方式1增幅(金币和矛盾)
         *    4.1.用户的金币够吗? 用户的矛盾够吗? 不够抛出异常
         *    4.2.够的话,先扣除用户的金币和矛盾数量
         *  5.如果用户通过方式2增幅(增幅器)
         *    5.1. 增幅器够吗? 不够抛出异常
         *    5.2. 够的话,扣除增幅器数量
         *  6.开始增幅
         *    6.1.通过3可以得到装备强化的详细信息
         *    6.2 如果成功,等级+1
         *      6.2.1.将名望,装备等级,数值 更新到userWeapon
         *    6.3 如果失败?
         *      6.3.1. 等级小于等于10,将名望,装备等级,数值 更新到userWeapon
         *      6.3.2. 等级大于10,删除该装备
         */
        // 0
        const userItems = await tr.findBy(UserItem, { user: { id: userId } });
        // 1
        const money = await tr.findOneByOrFail(Money, {
          user: { id: userId },
          priceType: 1, // 是现金
        });
        // 2
        const userWeapon = await tr.findOneOrFail(UserWeapon, {
          where: { id },
          relations: { weapon: true },
        });
        // 3
        const weaponUp = await tr.findOneByOrFail(WeaponUp, {
          weaponType: userWeapon.weapon.weaponType,
          level: userWeapon.level + 1,
        });
        // 4
        if (upType === 1) {
          const userMoney = money.num;
          // itemType等于2是矛盾
          const userItemMaodun = userItems.find((item) => item.itemType === 2);
          if (!userItemMaodun) {
            throw new Error('没有矛盾');
          }
          if (userMoney - weaponUp.cost < 0) {
            throw new Error('金币不够了');
          }
          if (userItemMaodun.itemNum - weaponUp.maodun < 0) {
            throw new Error('矛盾不足');
          }
          // 4.1
          await tr.decrement(Money, { id: money.id }, 'num', weaponUp.cost);
          await tr.decrement(
            UserItem,
            { id: userItemMaodun.id },
            'itemNum',
            weaponUp.maodun,
          );
        } else if (upType === 2) {
          // 5
          const userItemUp = userItems.find((item) => item.itemType === 1);
          // 5.1
          if (!userItemUp) {
            throw new Error('没有增幅器');
          }
          if (userItemUp.itemNum - 1 < 0) {
            throw new Error('增幅器不足');
          }
          // 5.2
          await tr.decrement(UserItem, { id: userItemUp.id }, 'itemNum', 1);
        } else {
          throw new Error('还有其他选择??????????');
        }
        // 6.开始增幅
        const randomNum = getRandomFrom(1, 10000);
        // 6.2
        if (weaponUp.percent >= randomNum) {
          userWeapon.level += 1;
          userWeapon.fame = weaponUp.fame;
          userWeapon.num = weaponUp.num;
          await tr.update(UserWeapon, { id: userWeapon.id }, userWeapon);
          return {
            weaponId: userWeapon.weapon.id,
            weaponUpId: weaponUp.id,
            success: 1,
            type: 4,
            destroy: false,
            randomNum,
            errorMessage: `+${userWeapon.level - 1}的装备『${
              userWeapon.weapon.name
            }』到+${userWeapon.level}成功`,
          };
        } else {
          const beginLevel = userWeapon.level;
          const downToLevel = userWeapon.level - weaponUp.downLevel;
          // 6.3.1
          if (weaponUp.level <= 10) {
            const weaponUpDown = await tr.findOneByOrFail(WeaponUp, {
              weaponType: userWeapon.weapon.weaponType,
              level: downToLevel,
            });
            userWeapon.level = downToLevel;
            userWeapon.fame = weaponUpDown.fame;
            userWeapon.num = weaponUpDown.num;
            await tr.update(UserWeapon, { id: userWeapon.id }, userWeapon);
            return {
              weaponId: userWeapon.weapon.id,
              weaponUpId: weaponUp.id,
              success: 0,
              randomNum,
              type: 4,
              destroy: false,
              errorMessage: `装备『${userWeapon.weapon.name}』从+${beginLevel}掉落到+${downToLevel}`,
            };
          } else {
            // 6.3.2
            await tr.softDelete(UserWeapon, { id });
            return {
              weaponId: userWeapon.weapon.id,
              weaponUpId: weaponUp.id,
              success: 0,
              randomNum,
              type: 5,
              destroy: true,
              errorMessage: `+${beginLevel}的装备『${userWeapon.weapon.name}』碎了`,
            };
          }
        }
      })
      .then(async (result) => {
        await this.recordService.insertValues({
          user: { id: userId },
          userWeapon: { id },
          weapon: { id: result.weaponId },
          weaponUp: { id: result.weaponUpId },
          success: result.success,
          errorMessage: result.errorMessage,
          type: result.type,
        });
        return new UpWeaponResultVo(
          !!result.success,
          result.destroy,
          result.randomNum,
        );
      })
      .catch(async (err: Error) => {
        await this.recordService.insertValues({
          user: { id: userId },
          userWeapon: { id },
          success: 0,
          errorMessage: err.message,
          type: 4,
        });
        throw new Error(err.message);
      });
  }
}
